package com.regent.central.bill.service.bean.mrp;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.regent.central.bill.common.ActionType;
import com.regent.central.bill.common.BillPurchaseArriveStatus;
import com.regent.central.bill.common.DataChangeType;
import com.regent.central.bill.common.DateUtil;
import com.regent.central.bill.core.mrp.*;
import com.regent.central.bill.repository.mrp.*;
import com.regent.central.bill.repository.mrp.dto.BillMaterialArriveAddDTO;
import com.regent.central.bill.repository.mrp.dto.MaterialArriveDTO;
import com.regent.central.bill.repository.mrp.dto.arrive.*;
import com.regent.central.bill.repository.page.Pagination;
import com.regent.central.bill.service.bean.mrp.util.MrpOrderNoGenerateUtil;
import com.regent.central.bill.service.mrp.BillMaterialArriveService;
import com.regent.central.bill.service.mrp.BillMaterialPurchaseService;
import com.regent.central.bill.service.mrp.BillMaterialPurchaseSkuService;
import com.regent.central.bill.service.mrp.exception.MrpServiceException;
import com.regent.central.infrastructure.common.Uid;
import com.regent.central.infrastructure.service.bean.DomainServiceBean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
public class BillMaterialArriveServicesBean extends DomainServiceBean<BillMaterialArriveMapper, BillMaterialArrive> implements BillMaterialArriveService {

    @Resource
    private ActionMaterialArriveMapper actionMaterialArriveMapper;

    @Resource
    private BillMaterialPurchaseActionsMapper billMaterialPurchaseActionsMapper;

    @Resource
    private BillMaterialArriveActionsMapper billMaterialArriveActionsMapper;

    @Resource
    private BillMaterialArriveMapper billMaterialArriveMapper;

    @Resource
    private BillMaterialPurchaseService billMaterialPurchaseService;

    @Resource
    private ActionMaterialArriveCheckShrunkMapper actionMaterialArriveCheckShrunkMapper;

    @Resource
    private BillMaterialPurchaseSkuService billMaterialPurchaseSkuService;

    @Transactional
    @Override
    public BillMaterialArriveCreateResult create(BillMaterialArriveAddDTO dto) {
        BillMaterialArriveCreateResult result = new BillMaterialArriveCreateResult();
        BillMaterialArrive billMaterialArrive = new BillMaterialArrive();
        billMaterialArrive.setId(Uid.random());
        billMaterialArrive.setBossUnitId(dto.getBossUnitId());
        billMaterialArrive.setUnitId(dto.getUnitId());
        billMaterialArrive.setCreatorId(dto.getCreatorId());
        billMaterialArrive.setCreatorName(dto.getCreatorName());
        Date dateArrive = dto.getDateArrive();
        billMaterialArrive.setDateArrive(dateArrive == null ? new Date() : DateUtil.merge(dateArrive, new Date()));
        String orderNo = dto.getOrderNo();
        if (StringUtils.isEmpty(orderNo)) {
            orderNo = getOrderNumber(dto.getUnitId());
        }
        billMaterialArrive.setOrderNo(orderNo);
        billMaterialArrive.setStorehouseId(dto.getStorehouseId());
        billMaterialArrive.setSupplierId(dto.getSupplierId());
        billMaterialArriveMapper.insertSelective(billMaterialArrive);

        List<BillMaterialArriveAddDTO.ArriveAddMaterialsSkuDTO> materialsSkus = dto.getMaterialsSkus();
        Set<ActionMaterialArrive> actionMaterialArrives = new HashSet<>();
        for (BillMaterialArriveAddDTO.ArriveAddMaterialsSkuDTO sku : materialsSkus) {
            ActionMaterialArrive actionMaterialArrive = new ActionMaterialArrive();
            actionMaterialArrive.setId(Uid.random());
            actionMaterialArrive.setCentralBillMaterialPurchaseId(sku.getBillMaterialPurchaseId());
            actionMaterialArrive.setCommonMaterialsId(sku.getMaterialsId());
            actionMaterialArrive.setCommonMaterialsSkuId(sku.getMaterialsSkuId());
            actionMaterialArrive.setCommonMaterialsNo(sku.getMaterialsNo());
            actionMaterialArrive.setFacMissionId(sku.getFacMissionId());
            actionMaterialArrive.setPriceUnit(sku.getPriceUnit());
            actionMaterialArrive.setQuantity(sku.getQuantity());
            actionMaterialArrive.setStyleNo(sku.getStyleNo());
            Integer type = sku.getType();
            if (StringUtils.isEmpty(actionMaterialArrive.getFacMissionId())) {
                type = 1;
            }
            actionMaterialArrive.setType(type);
            BigDecimal priceTotal = sku.getPriceUnit().multiply(sku.getQuantity());
            actionMaterialArrive.setPriceTotal(priceTotal);
            actionMaterialArriveMapper.insertSelective(actionMaterialArrive);

            if (sku.isManualArriveComplete()) {
                // 如果用户选了手动到齐
                billMaterialPurchaseSkuService.setArriveStatus(BillPurchaseArriveStatus.COMPLETED, actionMaterialArrive.getCentralBillMaterialPurchaseId(),
                        sku.getFacMissionId(), sku.getMaterialsSkuId(), DataChangeType.USER_OPERATE);
            }

            actionMaterialArrives.add(actionMaterialArrive);
        }

        // 建立到料动作与采购单及到料单的关系
        Set<String> billPurchaseIds = new HashSet<>();
        for (ActionMaterialArrive actionMaterialArrive : actionMaterialArrives) {
            // 采购单
            BillMaterialPurchaseActions purchaseActions = new BillMaterialPurchaseActions();
            purchaseActions.setId(Uid.random());
            purchaseActions.setActionId(actionMaterialArrive.getId());
            purchaseActions.setCentralBillMaterialPurchaseId(actionMaterialArrive.getCentralBillMaterialPurchaseId());
            purchaseActions.setActionType(ActionType.MATERIAL_ARRIVE.name());
            billMaterialPurchaseActionsMapper.insertSelective(purchaseActions);

            billPurchaseIds.add(purchaseActions.getCentralBillMaterialPurchaseId());

            // 到料单
            BillMaterialArriveActions arriveActions = new BillMaterialArriveActions();
            arriveActions.setId(Uid.random());
            arriveActions.setActionId(actionMaterialArrive.getId());
            arriveActions.setActionType(ActionType.MATERIAL_ARRIVE.name());
            arriveActions.setCentralBillMaterialArriveId(billMaterialArrive.getId());
            billMaterialArriveActionsMapper.insertSelective(arriveActions);
        }

        // 维护采购单到料状态
        for (String billPurchaseId : billPurchaseIds) {
            billMaterialPurchaseService.keepBillPurchaseArriveStatus(billPurchaseId);
        }

        result.setBillMaterialArriveId(billMaterialArrive.getId());
        result.setSuccess(true);
        return result;
    }

    @Override
    public String getOrderNumber(String unitId) {
        LocalDate now = LocalDate.now();
        String startDate = now.toString() + " 00:00:00";
        String endDate = now.toString() + " 23:59:59";
        LocalDateTime dateStart = LocalDateTime.parse(startDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        LocalDateTime dateEnd = LocalDateTime.parse(endDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        int count = billMaterialArriveMapper.countBillArriveByUnitId(unitId, dateStart, dateEnd);
        return MrpOrderNoGenerateUtil.generate(count, "DL");
    }

    @Override
    public BillMaterialArriveDetailDTO detail(String billMaterialArriveId) {
        BillMaterialArriveDetailDTO billMaterialArriveDetailDTO = billMaterialArriveMapper.getDetail(billMaterialArriveId);

        ArriveActionDetailDTO arriveActionDetailDTO = new ArriveActionDetailDTO();
        List<ArriveDetailSkuDTO> skus = billMaterialArriveMapper.listArriveActionDetail(billMaterialArriveId);
        arriveActionDetailDTO.setSkus(skus);
        Set<String> skuIds = new HashSet<>();
        BigDecimal amountTotal = BigDecimal.ZERO;
        for (ArriveDetailSkuDTO arriveDetailSkuDTO : skus) {
            skuIds.add(arriveDetailSkuDTO.getMaterialsSkuId());
            amountTotal = amountTotal.add(arriveDetailSkuDTO.getPriceTotal());
        }
        arriveActionDetailDTO.setQuantitySku(skuIds.size());
        arriveActionDetailDTO.setAmountTotal(amountTotal);
        billMaterialArriveDetailDTO.setArriveActionDetail(arriveActionDetailDTO);

        List<ActionCheckShrunkDTO> actionCheckShrunks = billMaterialArriveMapper.listCheckShrunks(billMaterialArriveId);
        billMaterialArriveDetailDTO.setActionCheckShrunks(actionCheckShrunks);
        return billMaterialArriveDetailDTO;
    }

    @Override
    public List<MaterialSkuCSDTO> csMaterialSku(String billMaterialArriveId) {
        return mapper.csMaterialSku(billMaterialArriveId);
    }

    @Transactional
    @Override
    public void check(ArriveCheckDTO arriveCheckDTO) throws MrpServiceException {
        String checkerId = arriveCheckDTO.getCheckerId();
        String dateCheck = arriveCheckDTO.getDateCheck();
        List<ArriveCheckShrunkOprDTO> skus = arriveCheckDTO.getSkus();
        ShrunkStockChangeDTO stockChange = arriveCheckDTO.getStockChange();
        List<ArriveCheckShrunkStockChangeDTO> stockChanges = stockChange.getStockChanges();

        for (ArriveCheckShrunkOprDTO sku : skus) {
            String billMaterialArriveId = sku.getBillMaterialArriveId();
            String materialSkuId = sku.getMaterialSkuId();
            ActionMaterialArriveCheckShrunk checkShrunk = actionMaterialArriveCheckShrunkMapper.getByBillArriveAndSku(billMaterialArriveId, materialSkuId);
            if (checkShrunk == null) {
                checkShrunk = new ActionMaterialArriveCheckShrunk();
                checkShrunk.setId(Uid.random());
                checkShrunk.setCentralBillMaterialArriveId(billMaterialArriveId);
                checkShrunk.setCheckerId(checkerId);
                checkShrunk.setCommonMaterialsSkuId(sku.getMaterialSkuId());
                checkShrunk.setLengthCheck(sku.getLength());
                checkShrunk.setDateCheck(DateUtil.formartToDate(dateCheck, "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd"));
                checkShrunk.setTotalArrive(sku.getTotalArrive());
                checkShrunk.setChecked(true);
                actionMaterialArriveCheckShrunkMapper.insertSelective(checkShrunk);

            } else if (!checkShrunk.getChecked()) {
                checkShrunk.setLengthCheck(sku.getLength());
                checkShrunk.setChecked(true);
                checkShrunk.setDateCheck(DateUtil.formartToDate(dateCheck, "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd"));
                checkShrunk.setCheckerId(checkerId);
                actionMaterialArriveCheckShrunkMapper.updateByPrimaryKeySelective(checkShrunk);
            } else {
                // 验过布的不能再验布了
                throw new MrpServiceException("该物料已经做过验布, 请核对");
            }
        }

        // 关联库存ID
        checkStockChange(stockChanges);
    }

    @Transactional
    @Override
    public List<ArriveShrunkStockChangeResult> shrunk(ArriveShrunkDTO arriveShrunkDTO) throws MrpServiceException {
        List<ArriveShrunkStockChangeResult> results = new ArrayList<>();

        String shrunkerId = arriveShrunkDTO.getShrunkerId();
        String dateShrunk = arriveShrunkDTO.getDateShrunk();
        List<ArriveCheckShrunkOprDTO> skus = arriveShrunkDTO.getSkus();

        for (ArriveCheckShrunkOprDTO sku : skus) {
            String billMaterialArriveId = sku.getBillMaterialArriveId();
            String materialSkuId = sku.getMaterialSkuId();
            ArriveShrunkStockChangeResult result = new ArriveShrunkStockChangeResult();
            result.setMaterialSkuId(sku.getMaterialSkuId());
            ActionMaterialArriveCheckShrunk checkShrunk = actionMaterialArriveCheckShrunkMapper.getByBillArriveAndSku(billMaterialArriveId, materialSkuId);
            if (checkShrunk == null) {
                checkShrunk = new ActionMaterialArriveCheckShrunk();
                checkShrunk.setId(Uid.random());
                checkShrunk.setCentralBillMaterialArriveId(billMaterialArriveId);
                checkShrunk.setCommonMaterialsSkuId(sku.getMaterialSkuId());
                checkShrunk.setShrunkerId(shrunkerId);
                checkShrunk.setLengthShrunk(sku.getLength());
                checkShrunk.setDateShrunk(DateUtil.formartToDate(dateShrunk, "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd"));
                checkShrunk.setTotalArrive(sku.getTotalArrive());
                checkShrunk.setShrunked(true);

                // 如果缩布的时候还没做过验布, 自动按照【验布长度=到料长度】进行赋值
                checkShrunk.setChecked(true);
                checkShrunk.setDateCheck(DateUtil.formartToDate(dateShrunk, "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd"));
                checkShrunk.setLengthCheck(sku.getTotalArrive());
                checkShrunk.setCheckerId(shrunkerId);
                actionMaterialArriveCheckShrunkMapper.insertSelective(checkShrunk);
            } else if (!checkShrunk.getShrunked()) {
                // 缩过布的不能再缩布了
                if (!checkShrunk.getShrunked()) {
                    // 如果缩布的时候还没做过验布, 自动按照【验布长度=到料长度】进行赋值
                    checkShrunk.setChecked(true);
                    checkShrunk.setDateCheck(DateUtil.formartToDate(dateShrunk, "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd"));
                    checkShrunk.setLengthCheck(sku.getTotalArrive());
                    checkShrunk.setCheckerId(shrunkerId);
                }
                checkShrunk.setLengthShrunk(sku.getLength());
                checkShrunk.setShrunked(true);
                checkShrunk.setDateShrunk(DateUtil.formartToDate(dateShrunk, "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd"));
                checkShrunk.setShrunkerId(shrunkerId);
                actionMaterialArriveCheckShrunkMapper.updateByPrimaryKeySelective(checkShrunk);
            } else {
                throw new MrpServiceException("该物料已经做过缩布, 请核对");
            }
            result.setBillMaterialArriveId(sku.getBillMaterialArriveId());
            result.setQuantityOut(checkShrunk.getLengthShrunk().subtract(checkShrunk.getLengthCheck()).abs());
            results.add(result);
        }
        return results;
    }

    @Transactional
    @Override
    public void checkStockChange(List<ArriveCheckShrunkStockChangeDTO> stockChanges) {
        for (ArriveCheckShrunkStockChangeDTO stockChange : stockChanges) {
            String billMaterialArriveId = stockChange.getBillMaterialArriveId();
            String materialSkuId = stockChange.getMaterialSkuId();
            String stockChangeId = stockChange.getStockChangeId();
            actionMaterialArriveCheckShrunkMapper.checkStockChange(billMaterialArriveId, materialSkuId, stockChangeId);
        }
    }

    @Transactional
    @Override
    public void shrunkStockChange(List<ArriveCheckShrunkStockChangeDTO> stockChanges) {
        for (ArriveCheckShrunkStockChangeDTO stockChange : stockChanges) {
            String billMaterialArriveId = stockChange.getBillMaterialArriveId();
            String materialSkuId = stockChange.getMaterialSkuId();
            String stockChangeId = stockChange.getStockChangeId();
            actionMaterialArriveCheckShrunkMapper.shrunkStockChange(billMaterialArriveId, materialSkuId, stockChangeId);
        }
    }

    @Transactional
    @Override
    public UndoCheckResult undoCheck(String billMaterialArriveId, String materialSkuId) {
        UndoCheckResult result = new UndoCheckResult();
        int effectCount = billMaterialArriveMapper.undoCheck(billMaterialArriveId, materialSkuId);
        result.setEffectCount(effectCount);
        if (effectCount <= 0) {
            result.setSuccess(false);
            return result;
        }

        // 获取验布关联的库存变动记录
        String checkArriveStockChangeId = billMaterialArriveMapper.getCheckArriveStockChangeId(billMaterialArriveId, materialSkuId);
        result.setStockChangeId(checkArriveStockChangeId);
        return result;
    }

    @Transactional
    @Override
    public UndoShrunkResult undoShrunk(String billMaterialArriveId, String materialSkuId) {
        UndoShrunkResult result = new UndoShrunkResult();
        int effectCount = billMaterialArriveMapper.undoShrunk(billMaterialArriveId, materialSkuId);
        result.setEffectCount(effectCount);
        if (effectCount <= 0) {
            result.setSuccess(false);
            return result;
        }

        // 获取验布关联的库存变动记录
        String shrunkArriveStockChangeId = billMaterialArriveMapper.getShrunkArriveStockChangeId(billMaterialArriveId, materialSkuId);
        result.setStockChangeId(shrunkArriveStockChangeId);
        return result;
    }

    @Override
    public BillMaterialArrivePageDTO listMaterialArrive(BillMaterialArriveQueryDTO billMaterialArriveQueryDTO, int pageNum, int pageSize) {
        pageNum = pageNum <= 0 ? 1 : pageNum;
        pageSize = pageSize <= 0 ? 20 : pageSize;

        Page<String> page = PageHelper.startPage(pageNum, pageSize);
        billMaterialArriveMapper.listBillMaterialsArriveIds(billMaterialArriveQueryDTO);

        List<MaterialArriveDTO> materialArriveDTOS = new ArrayList<>();
        if (page.size() > 0) {
            materialArriveDTOS = billMaterialArriveMapper.listMaterialArriveByBillArriveIds(page);
        }

        BillMaterialArrivePageDTO billMaterialArrivePageDTO = new BillMaterialArrivePageDTO();
        Pagination<MaterialArriveDTO> pagination = new Pagination<>();
        pagination.setDataList(materialArriveDTOS);
        pagination.setPageSize(pageSize);
        pagination.setPageNum(pageNum);
        pagination.setTotal((int) page.getTotal());
        billMaterialArrivePageDTO.setList(materialArriveDTOS);
        billMaterialArrivePageDTO.setPagination(pagination);
        return billMaterialArrivePageDTO;
    }

    @Override
    public List<MaterialArriveDTO> arriveExcel(BillMaterialArriveQueryDTO billMaterialArriveQueryDTO){
        List<MaterialArriveDTO> materialArriveDTOS = billMaterialArriveMapper.arriveExcel(billMaterialArriveQueryDTO);
        return materialArriveDTOS;
    }

    @Transactional
    @Override
    public BillArriveUndoResult undo(String billMaterialArriveId) {
        BillArriveUndoResult result = new BillArriveUndoResult();
        // 看下有没有验布或者缩布, 有的话不能撤销
        boolean hasCheckShrunked = billMaterialArriveMapper.hasCheckShrunked(billMaterialArriveId);
        if (hasCheckShrunked) {
            result.setSuccess(false);
            return result;
        }

        int effectCountBill = billMaterialArriveMapper.undoBill(billMaterialArriveId);
        if (effectCountBill <= 0) {
            result.setSuccess(false);
            return result;
        }
        int effectCountAction = billMaterialArriveMapper.undoAction(billMaterialArriveId);
        if (effectCountAction <= 0) {
            result.setSuccess(false);
            return result;
        }

        List<BillArriveUndoMissionSkuDTO> skus = billMaterialArriveMapper.listArriveQuantity(billMaterialArriveId);
        result.setSkus(skus);

        String stockChangeId = billMaterialArriveMapper.getStockChangeId(billMaterialArriveId);
        result.setStockChangeId(stockChangeId);
        return result;
    }

    @Transactional
    @Override
    public void relationStockChange(String billMaterialArriveId, String stockChangeId) {
        billMaterialArriveMapper.relationStockChange(billMaterialArriveId, stockChangeId);
    }

    public List<String> findOrderNosByUnitId(String unitId){
        return billMaterialArriveMapper.findOrderNosByUnitId(unitId);
    }
}